#pragma once
#include <iostream>
#include <queue>
//交易场所，超市，特定结构的内存空间
template<class T>
class Blockqueue
{
    private:
    std::queue<T> blockqueue_;//队列

    //极值
    int maxcapacity_;//队列最大容量
    int mincapacity_=0;//队列最小容量
    pthread_mutex_t mutex_;
    pthread_cond_t cond_c;//消费者的条件变量（消费者到消费者的等待队列里等）
    pthread_cond_t cond_p;//生产者条件变量（生产者到生产者的等待队列里等）
    public:
    Blockqueue(int maxcapacity)
    {
        maxcapacity_=maxcapacity;
        pthread_mutex_init(&mutex_,nullptr);//初始化锁
        pthread_cond_init(&cond_c,nullptr);//初始化条件变量
        pthread_cond_init(&cond_p,nullptr);//初始化条件变量

    }
    ~Blockqueue()
    {
        pthread_mutex_destroy(&mutex_);//销毁锁
        pthread_cond_destroy(&cond_c);//销毁条件变量
        pthread_cond_destroy(&cond_p);//销毁条件变量

    }
    void push(const T& val)
    {
        //访问共享资源前先上锁
        pthread_mutex_lock(&mutex_);
        //生产有条件的，先判断队列里是否满，满了就去等待被唤醒
        while(blockqueue_.size()==maxcapacity_)
        {
            pthread_cond_wait(&cond_p,&mutex_);//去生产者队列里面等待，并解锁，被唤醒后重新获取锁
        }
        //走到这里说明： 1、队列里的数据不为满 2、被唤醒
        blockqueue_.push(val);
        //生产一个数据后唤醒消费者
        pthread_cond_signal(&cond_c);
        //结束后解锁
        pthread_mutex_unlock(&mutex_);
    }
    T pop()
    {
        //在访问共享数据前先上锁（blockqueue就是共享资源）
        pthread_mutex_lock(&mutex_);
        while(blockqueue_.size()==mincapacity_)//如果共享空间里没有数据就让线程去等待
        {
            pthread_cond_wait(&cond_c,&mutex_);//到消费者队列里等，等待并解锁，被唤醒后自动去获取锁
        }
        //到这一步说明1.共享空间有数据或者 2. 被唤醒
            T top=blockqueue_.front();
        blockqueue_.pop();//消费一个数据就唤醒生产者
        pthread_cond_signal(&cond_p);
        //访问结束后解锁
        pthread_mutex_unlock(&mutex_);
        return top;
    }
};